home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / programming / other / gui4cli / ext / gcsound / src / gcsound.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  15KB  |  479 lines

  1.  
  2. /***********************************************************************
  3. *
  4. *    GCSound 1.0 - D. Keletsekis (October 98)
  5. *
  6. *    compile: SC GCSound  NOSTACKCHECK  LINK  NOSTARTUP
  7. *    ..or have a look at the scoptions files..
  8. *
  9. *    This is a "host" program for playing 8SVX sound samples.
  10. *    It can understand commands from ARexx or Gui4Cli and
  11. *    load & play many samples together, multitaskinglisingly..
  12. *
  13. *    The name of the port opened is "gcsound" (note lower case)
  14. *
  15. *    These are the current commands :
  16. *
  17. *    QUIT    - abort all sounds and quit
  18. *    LOAD    <SampleFile> <Alias> (default speed/time/volume)
  19. *    PLAY    <alias> <times/0> <volume> <speed/-1> 
  20. *    SOUND   <SampleFile> <times/0> <volume> <speed/-1> (load, play & quit)
  21. *    VOLUME  <alias> <1-64>
  22. *    SPEED   <alias> <?>
  23. *    TIMES   <alias> <times/0>
  24. *    INFO    <alias> (return "volume speed")
  25. *    UNLOAD  <alias> (or "" for all samples - stop & unload)
  26. *    STOP    <alias> (or "" for all samples - stop playing)
  27. *
  28. *    From Gui4Cli they can be called either with :
  29. *    -> Call gcsound command arguments..        -or-
  30. *    -> SendRexx gcsound "command arguments"    (note the quotes)
  31. *
  32. ************************************************************************/
  33. #define __USESYSBASE
  34. #include <exec/exec.h>
  35. #include <exec/execbase.h>
  36. #include <exec/memory.h>
  37. #include <dos/dosextens.h>
  38. #include <dos/rdargs.h>
  39. #include <dos/dostags.h>
  40. #include <devices/audio.h>
  41. #include <graphics/gfxbase.h>
  42. #include <string.h>
  43. #include <stdio.h>
  44. #include <ctype.h>
  45. #include <dos.h>
  46. #include <proto/dos.h>
  47. #include <proto/exec.h>
  48. #include <proto/rexxsyslib.h>
  49. #include <graphics/text.h>
  50. #include <rexx/storage.h>
  51. #include <datatypes/soundclass.h>    // include soundclass
  52.  
  53. #include "Gui4Cli.h"        // include Gui4Cli.h (for the message structure)
  54.  
  55. #include "gcsound_protos.h"
  56.  
  57. static const char VERSION[] = "\0$VER: gcsound 1.0 (D.Keletsekis Oct.98)";
  58.  
  59. #define BUFFER_SIZE 65536     // the buffer size (should be a tooltype)
  60. #define CLEANMEM (MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC)
  61.  
  62. // We use this "treat a 4 character string as if it were a LONG
  63. // integer" ID method for identifying our commands also.
  64. // This means that *only* the first four letters of each command
  65. // are checked - but it allows us to use a fast case statement.
  66. #define MakeID(a,b,c,d)    ((LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d))
  67. #define QUIT     MakeID('Q','U','I','T')
  68. #define LOAD     MakeID('L','O','A','D')
  69. #define PLAY     MakeID('P','L','A','Y')
  70. #define SOUND     MakeID('S','O','U','N')
  71. #define VOLUME     MakeID('V','O','L','U')
  72. #define SPEED     MakeID('S','P','E','E')
  73. #define TIMES     MakeID('T','I','M','E')
  74. #define INFO     MakeID('I','N','F','O')
  75. #define UNLOAD     MakeID('U','N','L','O')
  76. #define STOP     MakeID('S','T','O','P')
  77. // #define ID_FORM    MakeID('F','O','R','M')
  78.  
  79. struct myhandle        // each sample has one of these..
  80. {
  81.    struct VoiceHeader vh;    // the 8SVX header
  82.    LONG   bodystart;        // offset of body start into file
  83.    LONG   bodylength;        // total body length
  84.    ULONG  speed;        // playback speed
  85.    ULONG  volume;        // volume (default=64)
  86.    ULONG  times;        // times to play
  87.    ULONG  played;        // times already played
  88.    UBYTE  *buff1, *buff2;    // the buffer pointers
  89.    LONG   buffsize;        // buffer size
  90.    BPTR   fp;            // the file pointer (if file is open)
  91.    char   path[256];        // full name & path of file
  92.    char   alias[40];        // alias - the given name (upper case)
  93.    struct IOAudio io1, io2;      // Pointers to Audio IO structures
  94.    BOOL   out1, out2;        // flags indicating msgs outstanding
  95.    ULONG  remain;        // remaining data length (large samples)
  96.    BOOL   reload;        // 1 = reload sample before replaying
  97.    BOOL   killflag;        // 1 = kill sample when all msgs replied
  98.    BOOL   playonce;        // 1 = SOUND - load/play/quit sample
  99.    struct base *bs;        // pointer to base
  100.    struct myhandle *next;
  101. };
  102.  
  103. struct base         // somewhere to hold everything
  104. {
  105.    struct myhandle *toph;    // top of handles linked list
  106.    struct MsgPort *soundport;    // our sound reply port
  107.    ULONG  clock;        // clock constant
  108.    UBYTE  retbuff[80];          // return text..
  109.    LONG   users;        // how many guis are using us
  110.    struct DosLibrary *dosbase;    // carry these around..
  111.    struct ExecBase *sysbase;
  112. };
  113.  
  114.  
  115. // ===============================================================
  116. //     MAIN() - note there is no need for a main() function
  117. //    The program starts at the 1st function it finds, which
  118. //    can be any name..
  119. // ===============================================================
  120.  
  121. int main(void)
  122. {
  123. // these are the libraries we need
  124. struct ExecBase *SysBase = (*((struct ExecBase **) 4));
  125. struct DosLibrary *DOSBase=NULL;
  126. struct Process *myself = (struct Process *)(SysBase->ThisTask);
  127. struct MsgPort *myport=NULL;        // our port
  128. ULONG  soundsig, portsig, sig;        // port signal masks
  129. struct g4cmsg  *msg;    // Gui4Cli message pointer
  130. int    rc = 10;     // return code
  131. BOOL   endflag = 0;    // control flags
  132. BOOL   errorflag = 0;
  133. struct base *bs=NULL;    // our base struct pointer
  134. struct myhandle *h, *hh;
  135. struct IOAudio *io;
  136. struct Task *mt=NULL;    // for bumping task priority
  137. BYTE   oldpri=0;
  138. LONG   readmore, ret;
  139. LONG   rxargs[6];        // for rexx msg parsing
  140. struct RDArgs *rdargs;
  141. struct RexxMsg *rxmsg;
  142. struct RexxSysBase *RexxSysBase = NULL;
  143.  
  144. // -------------------- open the dos library or die..
  145.  
  146. if (!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 36L)))
  147. {   myself->pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY;
  148.     goto endprog;
  149. }
  150.  
  151. // if rexx is not opened, rexx commands will not be executed
  152. RexxSysBase = (struct RexxSysBase *)OpenLibrary ("rexxsyslib.library", 36L);
  153.  
  154. // -------------------- if gcsound is already running ++users & quit
  155.  
  156. if (myport = FindPort("gcsound"))
  157. {   if (msg = (struct g4cmsg *)AllocVec(sizeof(struct g4cmsg), CLEANMEM))
  158.     {   msg->magic = 392002;  // the only thing that's checked
  159.     msg->node.mn_Length = sizeof(struct g4cmsg);
  160.     PutMsg (myport, &msg->node);
  161.     // msg will not be replied & *will* be freeveced
  162.     }
  163.     myport = NULL; // so that it's not freed
  164.     rc = 0;
  165.     goto endprog;
  166. }
  167.  
  168. // -------------------- get our main base structure
  169.  
  170. if (!(bs = (struct base *)AllocVec(sizeof(struct base), CLEANMEM)))
  171.     goto endprog;
  172. bs->sysbase = SysBase;
  173. bs->dosbase = DOSBase;
  174. bs->users   = 1; // the guy who loaded us is also our 1st user
  175. if (!getconstant(bs)) goto endprog;
  176.  
  177. // --------------------- increase our priority - why ?
  178.  
  179. mt = FindTask(NULL);
  180. oldpri = SetTaskPri(mt,21);
  181.  
  182. // --------------------- Open message ports or die..
  183.  
  184. bs->soundport = CreatePort(0,0);    // sound return port
  185. myport = openport ("gcsound", SysBase, DOSBase);  // G4C port
  186. if (!bs->soundport || !myport)
  187. {   PutStr ("Couldn't open ports!\n");
  188.     goto endprog;
  189. }
  190. portsig  = (1 << myport->mp_SigBit);   // create signal masks
  191. soundsig = (1 << bs->soundport->mp_SigBit);
  192.  
  193. // ---------------------- Main wait() & process loop
  194. // quit on endflag but after all samples have quit first
  195.  
  196. while ((!endflag) || (bs->toph))
  197. {
  198.    // wait on combined port signals
  199.    sig = Wait (portsig | soundsig);
  200.  
  201.    // ------------------- messages from Gui4Cli, ARexx etc
  202.  
  203.    // we support messages from an other instance of this program, or
  204.    // from Gui4Cli or from ARexx - we check to see what we got
  205.  
  206.    if (sig & portsig)
  207.    {
  208.        while (msg = (struct g4cmsg *)GetMsg(myport))
  209.        {
  210.        // if it's from an other instance of gcsound, ++users
  211.        if (msg->magic == 392002)
  212.        {   ++bs->users;
  213.            FreeVec (msg);  // do *not* reply - *do* FreeVec()
  214.        }
  215.  
  216.        else if (msg->magic == 392001)  // from gui4cli
  217.        {
  218.                // check that its like we expect it..
  219.                if ((msg->type == GM_COMMAND) && msg->gcmain && msg->com)
  220.                {
  221.                   ret = docommand ((*((LONG *)msg->com)), bs, msg->args[0], msg->args[1], msg->args[2], msg->args[3]);
  222.                   if (ret < 0) endflag = 1;       // quit
  223.                   else 
  224.                   {   // if there is a return, attach string
  225.                       if (bs->retbuff[0])
  226.                       {   if (msg->msgret = (UBYTE *)AllocVec(80, CLEANMEM))
  227.                               strcpy (msg->msgret, bs->retbuff);
  228.                           bs->retbuff[0] = '\0';
  229.                       }
  230.                       msg->res = ret;
  231.                   }  
  232.